<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
	<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
	<title>管理应用 | STAT HUB</title>
	<link type="text/css" rel="stylesheet" href="resource/css/framework.css" />
	<link type="text/css" rel="stylesheet" href="resource/css/main.css" />
	<link type="text/css" rel="stylesheet" href="resource/css/jquery.alerts.css" media="screen" />
	<link type="text/css" rel="stylesheet" href="resource/css/jquery.dropdown.css" />
	<script type="text/javascript" src="resource/javascript/jquery.min.js"></script>
	<script type="text/javascript" src="resource/javascript/jquery-ui.min.js"></script>
	<script type="text/javascript" src="resource/javascript/jquery.alerts.js"></script>
	<script type="text/javascript" src="resource/javascript/stathub.js"></script>
	<script type="text/javascript" src="resource/javascript/jquery.dropdown.js"></script>
	<style type="text/css">
		.hidden {
			display:none;
		}
	</style>
</head>
<body>
	<div class="page">
		<!--header begin-->
		<header>
			<div class="bigcontainer">
				<div id="logo">
					<a href="/">STAT HUB 应用管理</a>
				</div>
				<div class="user">
					<div class="ui compact notif menu">
						<a class="item" href="notifications.html">
							<i class="mail large icon"></i>
							<span id="message_count" class="circular floating ui small red label"></span>
						</a>
					</div>
					<div class="ui icon top right dropdown">
						<a href="user_profile.html">
							<img class="ui avatar image" src="resource/images/avatar-default.gif"/>
							欢迎，管理员
						</a>
					</div>
				</div>
			</div>
		</header>
		<!-- the main menu-->
		<div class="ui teal inverted menu">
			<div class="bigcontainer">
				<div class="right menu">
					<a class="item" href="/"><i class="home icon"></i>管理首页</a>
					<a class="item" href="node_list.html"><i class="sitemap icon"></i>节点</a>
					<a class="active item" href="app_list.html"><i class="cloud icon"></i>应用</a>
					<a class="item" href="help.html"><i class="help icon"></i>帮助</a>
					<a class="item" href="api_doc.html"><i class="info icon"></i>API接口</a>
				</div>
			</div>
		</div>
		<!--the main content begin-->
		<div class="container">
			<!--the content-->
			<div class="ui grid">
				<!--the vertical menu-->
				<div class="four wide column">
					<div class="verticalMenu">
						<div class="ui vertical pointing menu fluid">
							<a class="item" href="./new_app.html">
								<i class="rocket icon"></i> 部署新应用
							</a>
							<a class="active teal item" href="app_list.html">
								<i class="cloud icon"></i> 所有应用
							</a>
							<a class="item" href="app_stat.html">
								<i class="bar chart icon"></i> 应用统计
							</a>
						</div>
					</div>
				</div>
				<!--the App list-->
				<div class="twelve wide column">
					<div class="pageHeader">
						<div class="segment">
							<h3 class="ui dividing header">
								<i class="large cloud icon"></i>
								<div class="content">
									管理应用
									<div class="sub header">管理 <span id="app_name_title"></span> 应用和进程</div>
								</div>
							</h3>
						</div>
					</div>
					<!--the app info-->
					<div class="ui app two column middle aligned vertical grid segment">
						<div class="column verborder">
							<div id="error_app" class="ui left corner label error hidden"><div class="text">异常</div></div>
							<div class="ui info segment">
								<h5 class="ui header">
									<span id="app_name"></span>
									<span id="status_app"></span>
								</h5>
								<p>进程：<span id="proc_app" class="stress"></span></p>
								<p>资源：<span id="res_app"></span></p>
								<p>描述：<span id="desc_app"></span></p>
								<p>状态：<span id="stat_app" class="procStatus"></span></p>
							</div>
						</div>
						<div class="center aligned column">
							<div class="ui buttons">
								<a id="oper_button_app" class="ui tiny button"><i id="oper_i_app" class="icon"></i><span id="oper_s_app">启 动</span></a>
								<a id="choreo_button" class="ui tiny blue button"><i class="tasks icon"></i>编 排</a>
								<a id="edit_button" class="ui tiny blue button"><i class="edit icon"></i>修 改</a>
								<a id="delete_button" class="ui tiny basic button"><i class="trash icon"></i>删 除</a>
							</div>
						</div>
					</div>
					<div class="ui vertical segment">
						<div class="ui small left icon input">
							<input id="queryDisplay" type="text" style="width:150px" placeholder="输入主机名...">
							<input type="hidden" id="query" value="">
							<i class="search icon"></i>
							<a id="queryFilter" class="circular ui mini button" title="过滤">过滤</a>
							<a id="queryAll" class="circular ui mini button active" title="全部">全部</a>
						</div>
					</div>
					<!-- the proc table-->
					<table id="statustable" class="ui compact table">
						<tr>
							<th class="hidden">hidden</th>
							<th>操作</th>
							<th>主机</th>
							<th>PID</th>
							<th>时间</th>
							<th>命令</th>
							<th>端口</th>
						</tr>
					</table>
				</div>
			</div>
		</div>	
	</div>
	<!--footer begin-->
	<footer>
		<div id="copyrights">
			<div class="inset">
				<div class="bigcontainer">
					<div class="fl">
						<div class="logo"></div>
						<p>&copy; 2014 lane.cn@gmail.com <a href="https://github.com/lane-cn/stat" target="_blank">https://github.com/lane-cn/stat</a></p>
					</div>
				</div>
			</div>
		</div>
	</footer>
	<script>
	$(document).ready(function() {
		var name = requestParameter('name').name.replace('#', '');
		$.get('/v1/app/' + name, function(app, status, xhr) {
			show_app(app);
			show_stat(app.name);
			refresh_list(app.name);
		});
		setInterval(function() {
			show_stat(name);
			refresh_list(name);
		}, 5000);
		$('#queryFilter').click(function() {
			$('#queryFilter').addClass('active');
			$('#queryAll').removeClass('active');
			$('#query').val($('#queryDisplay').val());
			refresh_list(name);
		});
		$('#queryAll').click(function() {
			$('#queryAll').addClass('active');
			$('#queryFilter').removeClass('active');
			$('#queryDisplay').val('');
			$('#query').val($('#queryDisplay').val());
			refresh_list(name);
		});
	});
	
	function refresh_list(app) {
		var query = $('#query').val();
		$.get('/v1/app/' + app + '/proc?query=' + query, function(ps, status, xhr) {
			var signs = new Array();
			for (var i=0; i<ps.length; i++) {
				signs[i] = ps[i].pid + '@' + ps[i].node;
			}
			
			//remove deleted row
			var keys = get_table_keys();
			$.each(keys, function(i, key) {
				if ($.inArray(key, signs) < 0) {
					remove_row(key);
				}
			});
			
			//add new row
			$.each(ps, function(i, p) {
				var sign = p.pid + '@' + p.node;
				if ($.inArray(sign, keys) < 0) {
					add_row(p.pid, p.node);
					refresh_row(p.pid, p.node);
				}
			});
		});
	}
	
	function refresh_row(pid, node) {
		$.get('/v1/node/' + node + '/proc/' + pid, function(p, status, xhr) {
			update_row(p);
		});
	}
	
	function update_row(p) {
		$.get('/v1/node/' + p.node, function(node, status, xhr) {
			var address = node.agentAddress;
			var ary = address.split(':');
			address = ary[0] + ':' + ary[1];
			var text = new Array();
			$.each(p.ports, function(i, port) {
				text.push('<a href="' + address + ':' + port + '" target="_blank">' + port + '</a>');
			});
			
			$('#ppid_' + p.pid + '_' + p.node).text(p.ppid);
			$('#node_' + p.pid + '_' + p.node).html('<a href="' + node.agentAddress + '" target="_blank">' + node.hostname + '</a>');
			$('#stime_' + p.pid + '_' + p.node).text(p.startTime);
			$('#cmd_' + p.pid + '_' + p.node).text(p.cmd);
			$('#port_' + p.pid + '_' + p.node).html(text.join(', '));
		});
	}
	
	function add_row(pid, node) {
		var row = '<tr id="tr_' + pid + '_' + node + '" class="">';
		row += '<td class="hidden">' + pid + '@' + node + '</td>';
		row += '<td class="action">';
		row += '<div id="jq-dropdown-1_' + pid + '_' + node + '" class="jq-dropdown jq-dropdown-tip">';
		row += '<ul class="jq-dropdown-menu">';
		row += '<li><a href="health.html?node=' + node + '&pid=' + pid + '" target="_blank"><i class="basic icon"></i>查看健康检查日志</a></li>';
		row += '<li><a href="tail.html?node=' + node + '&pid=' + pid + '&out=stdout" target="_blank"><i class="basic icon"></i>查看标准输出</a></li>';
		row += '<li><a href="tail.html?node=' + node + '&pid=' + pid + '&out=stderr" target="_blank"><i class="basic icon"></i>查看错误输出</a></li>';
		row += '<li class="jq-dropdown-divider"></li>';
		row += '<li><a href="javascript:void(0)" onclick="kill(\'' + node + '\', ' + pid + ')"><i class="trash icon"></i>杀死进程</a></li>';
		row += '</ul>';
		row += '</div>';
		row += '<a href="javascript:void(0)" data-jq-dropdown="#jq-dropdown-1_' + pid + '_' + node + '"><i class="setting icon"></i></a>';
		row += '</td>';
		row += '<td><span id="node_' + pid + '_' + node + '"></span></td>';
		row += '<td><span id="pid_' + pid + '_' + node + '">' + pid + '</span></td>';
		row += '<td><span id="stime_' + pid + '_' + node + '"></span></td>';
		row += '<td><span id="cmd_' + pid + '_' + node + '"></span></td>';
		row += '<td><span id="port_' + pid + '_' + node + '"></span></td>';
		row += '</tr>';
		$("#statustable tr:last").after(row);
	}
	
	function kill(node, pid) {
		jConfirm('停止进程，需要继续吗？', '确认', function(r) {
			if (r) {
				$.post('/v1/node/' + node + '/proc/' + pid + '/_kill', function(data, status, xhr) {});
				jAlert('已经发出停止指令', '提示');
			}
		});
	}
	
	function remove_row(name) {
		var keys = get_table_keys();
		var pos = $.inArray(name, keys);
		if (pos >= 0) {
			$("#statustable tr:gt(0):eq(" + pos + ")").remove();
		}
	}
	
	function get_table_keys() {
		var keys = new Array();
		var key = '';
		$("#statustable tr td:nth-child(1)").each(function () {
			key = $(this).text();
			if (key) {
				keys.push(key);
			}
		});
		return keys;
	}
	
	function show_app(app) {
		$('#app_name_title').text(app.name);
		$('#app_name').text(app.name);
		set_button_status(app.name, app.start);
		if (app.start) {
			$('#status_app').html('<span class="ui type label green">启动</span>');
		} else {
			$('#status_app').html('<span class="ui type label black">停止</span>');
		}
		$('#choreo_button').attr('onclick', "window.location.href='choreo.html?app=" + app.name + "';");
		$('#edit_button').attr('onclick', "window.location.href='edit_app.html?name=" + app.name + "';");
		$('#delete_button').attr('onclick', "delete_app('" + app.name + "')");
		if (app.resAlloc) {
			var text = 'CPU ' + app.resAlloc.cpus + ' 核，内存 ' + byteCountToDisplaySize(app.resAlloc.mem) + '，磁盘空间 ' + byteCountToDisplaySize(app.resAlloc.disk);
			$('#res_app').html(text);
		} else {
			$('#res_app').text('不分配');
		}
		var cmd = '';
		if (app.toProcess) {
			cmd = app.toProcess + ' ';
		}
		if (app.args) {
			cmd += app.args.join(' ');
		}
		$('#desc_app').text(cmd);
	}

	function set_button_status(app_name, start) {
		if (start) {
			$('#status_app').html('<span class="ui type label green">启动</span>');
			$('#oper_button_app').removeClass("green");
			$('#oper_button_app').addClass("black");
			$('#oper_i_app').removeClass("play");
			$('#oper_i_app').addClass("stop");
			$('#oper_s_app').text("停 止");
			$('#oper_button_app').attr('onclick', "stop_app('" + app_name + "')");
		} else {
			$('#status_app').html('<span class="ui type label black">停止</span>');
			$('#oper_button_app').addClass("green");
			$('#oper_button_app').removeClass("black");
			$('#oper_i_app').addClass("play");
			$('#oper_i_app').removeClass("stop");
			$('#oper_s_app').text("启 动");
			$('#oper_button_app').attr('onclick', "start_app('" + app_name + "')");
		}
	}
	
	function show_stat(app_name) {
		$.get('/v1/app/' + app_name, function(app, status, xhr) {
			$.get('/v1/app/' + app_name + '/choreo', function(choreo, status, xhr) {
				$.get('/v1/app/' + app_name + '/proc', function(ps, status, xhr) {
					//app status
					set_button_status(app_name, app.start);
					//instance desc
					var scale = app.start ? choreo.scale : 0;
					var inst = "";
					if (scale == 0) {
						inst += '没有计划';
					} else {
						inst += '计划 ' + scale + ' 个';
						if (choreo.dist.length > 0) {
							var distinct = new Array();
							for (var i=0; i<choreo.dist.length; i++) {
								if ($.inArray(choreo.dist[i], distinct) < 0)
									distinct.push(choreo.dist[i]);
							}
							inst += ', 在 ' + distinct.length + ' 个节点上分配 ' + choreo.dist.length + ' 个';
							if (ps.length > 0) {
								inst += ', 运行 ' + ps.length + ' 个';
							} else {
								inst += ', 没有运行';
							}
						} else {
							inst += ', 没有分配';
						}
					}
					$('#proc_app').text(inst);
					//status desc
					$('#stat_app').empty();
					if (scale == 0) {
						$('#stat_app').append('无');
					} else {
						for (var i = 0; i < scale; i ++) {
							if (i < ps.length) {
								$('#stat_app').append('<span class="ui green ok label" ></span> ');
							} else if (i < choreo.dist.length) {
								$('#stat_app').append('<span class="ui orange error label" ></span> ');
							} else {
								$('#stat_app').append('<span class="ui red error label" ></span> ');
							}
						}
					}
					//error
					if (ps.length < scale) {
						$('#error_app').show();
						$('#error_app').removeClass('hidden');
					} else {
						$('#error_app').hide();
					}
				});
			});
		});
	}
	
	function start_app(name) {
		$.post('/v1/app/' + name + '/_start', function(data, status, xhr) {
			jAlert('已经对应用 ' + name + ' 发出启动指令', '提示');
		});
	}
	
	function stop_app(name) {
		jConfirm('是否要停止应用 ' + name + ' ？', '确认', function(r) {
			if (r) {
				$.post('/v1/app/' + name + '/_stop', function(data, status, xhr) {
					jAlert('已经对应用 ' + name + ' 发出停止指令', '提示');
				});
			}
		});
	}
	
	function delete_app(name) {
		jConfirm('是否要删除应用 ' + name + ' ，这个操作无法恢复？', '确认', function(r) {
			if (r) {
				$.ajax({
					url: '/v1/app/' + name,
					type: 'DELETE',
					contentType: 'application/json',
					dataType: 'json',
					success: function(data, status, xhr) {
						jAlert('已经删除应用 ' + name, '提示');
						$('#popup_ok').click(function() {
							window.location.href = 'app_list.html';
						});
					},
					error: function(xhr, status, error) {
						jAlert('保存失败，状态：' + error + ', 信息: ' + xhr.responseJSON.message, '提示');
					}
				});
			}
		});
	}
	</script>
</body>
</html>
